#include "clib_container_fifo_queue.h"
#include "../vector/clib_container_double_ended_vector.h"

struct clib_container_fifo_queue {
    struct clib_container_double_ended_vector *vector;

    void *(*mem_malloc_func)(size_t size);

    void (*mem_free_func)(void *block);

    void *(*mem_copy_func)(void *target,const void *src, size_t size);
};


int clib_container_fifo_queue_create_with_conf(struct clib_container_fifo_queue_conf *conf,
                                               struct clib_container_fifo_queue **q) {

    clib_check_if_true_return_value(conf == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(conf->mem_copy_func == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(conf->mem_malloc_func == NULL, CLIB_RES_PARAM_ERROR);
    clib_check_if_true_return_value(conf->mem_free_func == NULL, CLIB_RES_PARAM_ERROR);

    struct clib_container_fifo_queue *queue = conf->mem_malloc_func(sizeof(struct clib_container_fifo_queue));
    if (!queue) {
        return CLIB_RES_MEMORY_ERROR;
    }

    struct clib_container_double_ended_vector_conf vector_conf;

    vector_conf.init_capacity = 8;
    vector_conf.mem_copy_func = conf->mem_copy_func;
    vector_conf.mem_free_func = conf->mem_free_func;
    vector_conf.mem_malloc_func = conf->mem_malloc_func;


    struct clib_container_double_ended_vector *vector = NULL;
    int code = clib_container_double_ended_vector_create_with_conf(&vector_conf, &vector);
    if (code != CLIB_RES_OK) {
        return code;
    }
    if (!vector) {
        conf->mem_free_func(queue);
        return CLIB_RES_MEMORY_ERROR;
    }

    queue->vector = vector;
    queue->mem_malloc_func = conf->mem_malloc_func;
    queue->mem_free_func = conf->mem_free_func;
    queue->mem_copy_func = conf->mem_copy_func;

    *q = queue;
    return CLIB_RES_OK;
}


void clib_container_fifo_queue_destroy(struct clib_container_fifo_queue *queue) {
    clib_container_double_ended_vector_destroy(queue->vector);
    queue->mem_free_func(queue);
}

int clib_container_fifo_queue_peek(struct clib_container_fifo_queue *queue, void **out) {
    return clib_container_double_ended_vector_get_last(queue->vector, out);
}

int clib_container_fifo_queue_dequeue(struct clib_container_fifo_queue *queue, void **out) {
    return clib_container_double_ended_vector_remove_last(queue->vector, out);
}

int clib_container_fifo_queue_enqueue(struct clib_container_fifo_queue *queue, void *element) {
    return clib_container_double_ended_vector_add_first(queue->vector, element);
}

size_t clib_container_fifo_queue_get_current_size(struct clib_container_fifo_queue *queue) {
    return clib_container_double_ended_vector_get_current_size(queue->vector);
}